package com.swak.reactivex.threads.waitstrategy;

import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.swak.reactivex.threads.Barrier;
import com.swak.reactivex.threads.WaitStrategy;

public class BlockingWaitStrategy implements WaitStrategy {

	private final Lock lock = new ReentrantLock();
	private final Condition processorNotifyCondition = lock.newCondition();

	@Override
	public void waitFor(Barrier barrier) throws InterruptedException, TimeoutException {
		if (!this.checkBarrier(barrier)) {
			lock.lock();
			try {
				while (!this.checkBarrier(barrier)) {
					processorNotifyCondition.await();
				}
			} finally {
				lock.unlock();
			}
		}

		while (!this.checkBarrier(barrier)) {
			Thread.onSpinWait();
		}
	}

	@Override
	public void wakeup() {
		lock.lock();
		try {
			processorNotifyCondition.signalAll();
		} finally {
			lock.unlock();
		}
	}
}
